package com.sale.goods.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sale.common.core.constant.CacheNames;
import com.sale.common.core.exception.GlobalException;
import com.sale.common.core.utils.StringUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.mybatis.core.page.TableDataInfo;
import com.sale.common.redis.utils.CacheUtils;
import com.sale.common.satoken.utils.LoginHelper;
import com.sale.goods.domain.GoodsCalculate;
import com.sale.goods.domain.GoodsCancel;
import com.sale.goods.domain.GoodsCollection;
import com.sale.goods.domain.GoodsSource;
import com.sale.goods.domain.dto.*;
import com.sale.goods.domain.dto.single.GoodsCollectionSingle;
import com.sale.goods.domain.vo.GoodsCollectionVo;
import com.sale.goods.mapper.*;
import com.sale.goods.service.IGoodsCollectionService;
import com.sale.goods.service.IGoodsIncomeService;
import com.sale.order.api.RemoteCustomerService;
import com.sale.storage.api.RemotePurchaseReceiptService;
import com.sale.storage.api.vo.QuantityDataVo;
import com.sale.storage.api.vo.UpdateInvoicedQuantityVo;
import com.sale.system.api.RemoteAccountManagementService;
import com.sale.system.api.RemoteCodeService;
import com.sale.system.api.RemoteReviewService;
import com.sale.system.api.RemoteStaffManagementService;
import com.sale.system.api.domain.SysBalance;
import com.sale.system.api.domain.SysDictData;
import com.sale.system.api.domain.vo.SysAuditHistoryVo;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 收款单实现类
 * @Date 23-07-2 0
 * @Author hl
 **/
@RequiredArgsConstructor
@Service
public class GoodsCollectionServiceImpl implements IGoodsCollectionService {

    private final GoodsCollectionMapper goodsCollectionMapper;

    private final GoodsCalculateMapper goodsCalculateMapper;

    private final GoodsSourceMapper goodsSourceMapper;

    private final GoodsPaymentMapper goodsPaymentMapper;

    private final GoodsIncomeMapper goodsIncomeMapper;

    private final GoodsDisburseMapper goodsDisburseMapper;

    private final GoodsTurnMapper goodsTurnMapper;

    private final GoodsNuclearMapper goodsNuclearMapper;

    private final GoodsCostAdjustmentMapper goodsCostAdjustmentMapper;

    @DubboReference
    private final RemoteReviewService remoteReviewService;

    @DubboReference
    private final RemoteCodeService remoteCodeService;

    @DubboReference
    private final RemoteCustomerService remoteCustomerService;

    @DubboReference
    private final RemoteStaffManagementService remoteStaffManagementService;

    @DubboReference
    private final RemoteAccountManagementService remoteAccountManagementService;

    @DubboReference
    private final RemotePurchaseReceiptService remotePurchaseReceiptService;


    /**
     * 查询收款单
     *
     * @param goodSCollectionVo,pageQuery
     * @return 收款单集合
     */
    @Override
    public TableDataInfo<Map<String, String>> selectCollectionList(GoodsCollectionVo goodSCollectionVo, PageQuery pageQuery) {
        Page<Map<String, String>> page = goodsCollectionMapper.selectCollectionList(pageQuery.build(), this.buildQueryWrapper(goodSCollectionVo));
        //客户
        Map<String, String> map1 = remoteCustomerService.getOpenCustomerFinance();
        List<SysDictData> netArray3 = CacheUtils.get(CacheNames.SYS_DICT, "bill_state");
        Map<String, String> netMap3 = netArray3.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        //收款人
        Map<String, String> map2 = remoteStaffManagementService.selectAllStaffManagement();
        page.getRecords().stream().forEach(map -> {
            map.put("clientName", map1.get(map.get("clientCode")));
            map.put("businessName", map2.get(map.get("businessName")));
            map.put("collectionStatusDict", netMap3.get(map.get("collectionStatus")));
        });
        return TableDataInfo.build(page);
    }

    private Wrapper<GoodsCollectionVo> buildQueryWrapper(GoodsCollectionVo goodsCollectionVo) {
        String name = goodsCollectionVo.getBusinessName();
        if (StringUtils.isNotBlank(name)) {
            Long staffId = remoteStaffManagementService.selectStaffManagementName(name);
            goodsCollectionVo.setBusinessName(String.valueOf(staffId));
        }
        String client = goodsCollectionVo.getClientName();
        if (StringUtils.isNotBlank(client)) {
            goodsCollectionVo.setClientName(remoteCustomerService.getCodeByCustomerName(client));
        }
        QueryWrapper<GoodsCollectionVo> wrapper = Wrappers.query();
        wrapper
            .like(StringUtils.isNotBlank(goodsCollectionVo.getCollectionCode()), "collection_code", goodsCollectionVo.getCollectionCode())
            .eq(StringUtils.isNotBlank(goodsCollectionVo.getClientCode()), "client_code", goodsCollectionVo.getClientCode())
            .eq(StringUtils.isNotBlank(goodsCollectionVo.getBusinessName()), "business_name", goodsCollectionVo.getBusinessName())
            .eq(StringUtils.isNotBlank(goodsCollectionVo.getCollectionStatus()), "collection_status", goodsCollectionVo.getCollectionStatus())
            .eq(StringUtils.isNotBlank(goodsCollectionVo.getCancelStatus()), "cancel_status", goodsCollectionVo.getCancelStatus()).between(goodsCollectionVo.getBeginTime() != null && goodsCollectionVo.getEndTime() != null,
                "collection_time", goodsCollectionVo.getBeginTime(), goodsCollectionVo.getEndTime());
        return wrapper;
    }

    /**
     * 新增收款单
     *
     * @param goodsCollectionVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertCollection(GoodsCollectionVo goodsCollectionVo) throws Exception {
        GoodsCollection coll = new GoodsCollection();
        BeanUtils.copyProperties(goodsCollectionVo, coll);
        Long id = IdWorker.getId();
        coll.setCollectionId(id);
        //新增明细(账户)
        List<GoodsCalculate> list = goodsCollectionVo.getCalculateList();
        //收款金额
        BigDecimal b1 = new BigDecimal(0);
        for (GoodsCalculate calculate :
            list) {
            b1 = b1.add(calculate.getAmountReceived());
            calculate.setRelevanceId(id);
        }
        coll.setCollectionAmount(b1);
        //新增账号明细
        goodsCalculateMapper.insertBatch(list);
        //源单据集合
        List<GoodsSource> list1 = goodsCollectionVo.getSourceList();
        //本次核销金额
        BigDecimal b2 = new BigDecimal(0);
        //单据金额
        if (list1 != null) {
            //新增源单据信息
            for (GoodsSource goodsSource :
                list1) {
                goodsSource.setRelevanceId(id);
                b2 = b2.add(goodsSource.getThisAmount());
            }
            goodsSourceMapper.insertBatch(list1);
        }
        coll.setCollectionCancelAmount(b2);
        coll.setCollectionShouldAmount(b1);
        coll.setCollectionHasAmount(b2);
        BigDecimal b3 = b1.subtract(b2);
        coll.setCollectionNotAmount(b3);
        if (b2.signum() > 0) {
            if (b3.signum() > 0) {
                //部分核销
                coll.setCancelStatus(1);
            } else {
                //全部核销
                coll.setCancelStatus(3);
            }
        } else {
            //未核销
            coll.setCancelStatus(2);
        }
        //新增主列表
        coll.setCollectionStatus(1);

        String authorityCoding = remoteCodeService.authorityCoding("finance:collections:list");
        if (authorityCoding == null) {
            throw new GlobalException("未进行单据配置,单据编码生成失败");
        }
        coll.setCollectionCode(authorityCoding);
        int os = goodsCollectionMapper.insert(coll);
        return os;
    }

    /**
     * 查询单个收款单
     *
     * @param collectionId
     * @return int
     */
    @Override
    public GoodsCollectionSingle selectCollectionById(long collectionId) {
        GoodsCollection collection = goodsCollectionMapper.selectById(collectionId);
        GoodsCollectionSingle single = new GoodsCollectionSingle();
        BeanUtils.copyProperties(collection, single);
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", collectionId);
        List<GoodsCalculate> calculateList = goodsCalculateMapper.selectByMap(map);
        single.setCalculateList(calculateList);
        List<GoodsSource> sourceList = goodsSourceMapper.selectByMap(map);
        single.setSourceList(sourceList);
        return single;
    }

    /**
     * 删除单个收款单
     *
     * @param collectionId
     * @return int
     */
    @Override
    public int deleteCollectionById(Long collectionId) {
        int os = goodsCollectionMapper.deleteById(collectionId);
        //删除明细数据
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", collectionId);
        goodsCalculateMapper.deleteByMap(map);
        //删除源单据信息
        goodsSourceMapper.deleteByMap(map);
        return os;
    }

    /**
     * 修改收款单
     *
     * @param goodsCollectionVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateCollectionEdit(GoodsCollectionVo goodsCollectionVo) {
        if (goodsCollectionVo.getCollectionStatus().equals("4")) {
            SysAuditHistoryVo vo = new SysAuditHistoryVo();
            vo.setPerms("finance:collection:examine");
            vo.setAuditDoc(goodsCollectionVo.getCollectionCode());
            int is = remoteReviewService.editHistory(vo);
            if (is == 0) {
                throw new GlobalException("修改失败,未找到审核历史!");
            }
        }
        GoodsCollection coll = new GoodsCollection();
        BeanUtils.copyProperties(goodsCollectionVo, coll);
        Long id = coll.getCollectionId();
        //删除明细数据 并新增
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", id);
        goodsCalculateMapper.deleteByMap(map);
        //删除源单据信息
        goodsSourceMapper.deleteByMap(map);
        //新增明细(账户)
        List<GoodsCalculate> list = goodsCollectionVo.getCalculateList();
        //收款金额
        BigDecimal b1 = new BigDecimal(0);
        for (GoodsCalculate calculate :
            list) {
            b1 = b1.add(calculate.getAmountReceived());
            calculate.setRelevanceId(id);
        }
        coll.setCollectionAmount(b1);
        //新增账号明细
        goodsCalculateMapper.insertBatch(list);
        //源单据集合
        List<GoodsSource> list1 = goodsCollectionVo.getSourceList();
        //本次核销金额
        BigDecimal b2 = new BigDecimal(0);
        //单据金额
        if (list1 != null) {
            //新增源单据信息
            for (GoodsSource goodsSource :
                list1) {
                goodsSource.setRelevanceId(id);
                b2 = b2.add(goodsSource.getThisAmount());
            }
            goodsSourceMapper.insertBatch(list1);
        }
        coll.setCollectionCancelAmount(b2);
        coll.setCollectionShouldAmount(b1);
        coll.setCollectionHasAmount(b2);
        BigDecimal b3 = b1.subtract(b2);
        coll.setCollectionNotAmount(b3);
        if (b2.signum() > 0) {
            if (b3.signum() > 0) {
                //部分核销
                coll.setCancelStatus(1);
            } else {
                //全部核销
                coll.setCancelStatus(3);
            }
        } else {
            //未核销
            coll.setCancelStatus(2);
        }
        //新增主列表
        coll.setCollectionStatus(1);
        int os = goodsCollectionMapper.updateById(coll);
        return os;
    }


    /**
     * 提交审核
     *
     * @param collectionId
     * @return int
     */
    @Override
    public int submitReview(Long collectionId) {
        GoodsCollection coll = goodsCollectionMapper.selectById(collectionId);
        int status = coll.getCollectionStatus();
        if (status != 1) {
            throw new GlobalException("只有待提交状态才能进行提交审核");
        }
        GoodsCollection coll2 = new GoodsCollection();
        coll2.setCollectionId(collectionId);
        coll2.setCollectionStatus(2);
        return goodsCollectionMapper.updateById(coll2);
    }

    /**
     * 撤销审核
     *
     * @param collectionId
     * @return int
     */
    @Override
    public int deleteReview(Long collectionId) {
        GoodsCollection coll = goodsCollectionMapper.selectById(collectionId);
        int status = coll.getCollectionStatus();
        if (status != 2) {
            throw new GlobalException("只有待审核状态才能进行撤销审核");
        }
        GoodsCollection coll2 = new GoodsCollection();
        coll2.setCollectionId(collectionId);
        coll2.setCollectionStatus(1);
        return goodsCollectionMapper.updateById(coll2);
    }

    /**
     * 审核单据
     *
     * @param goodsCollectionVo
     * @return int
     */
    @Override
    public int goodSExamineReview(GoodsCollectionVo goodsCollectionVo) throws Exception {
        SysAuditHistoryVo sysAuditHistoryVo = new SysAuditHistoryVo();
        Long id = goodsCollectionVo.getCollectionId();
        GoodsCollection coll = goodsCollectionMapper.selectById(id);
        String perms = "finance:collection:examine";
        sysAuditHistoryVo.setPerms(perms);
        sysAuditHistoryVo.setModuleType(3);
        sysAuditHistoryVo.setAuditState(goodsCollectionVo.getAuditState());
        sysAuditHistoryVo.setAuditRemarks(goodsCollectionVo.getAuditOpinion());
        sysAuditHistoryVo.setAuditDoc(coll.getCollectionCode());
        sysAuditHistoryVo.setUserId(LoginHelper.getUserId());
        int data = remoteReviewService.getSequence(sysAuditHistoryVo);
        if (data == 0) {
            throw new GlobalException("未对该审核进行配置");
        }
        //1:通过，2：审核中，3：没权限 4:该人已经审核过
        GoodsCollection goods = new GoodsCollection();
        goods.setCollectionId(id);
        switch (data) {
            case 1:
                if (goodsCollectionVo.getAuditState() == 2) {
                    goods.setCollectionStatus(4);
                } else {
                    goods.setCollectionStatus(5);
                    Map<String, Object> map2 = new HashMap<>();
                    map2.put("relevance_id", id);
                    List<GoodsCalculate> calculateList = goodsCalculateMapper.selectByMap(map2);
                    List<SysBalance> list1 = new ArrayList<>();
                    for (GoodsCalculate calculate : calculateList) {
                        SysBalance sys = new SysBalance();
                        sys.setAccountsId(Long.parseLong(calculate.getCalculateAccount()));
                        sys.setBalance(calculate.getAmountReceived());
                        list1.add(sys);
                    }
                    int j = remoteAccountManagementService.editListBalance(list1);
                    if (j == 0) {
                        throw new GlobalException("未回传余额，请重试");
                    }
                    List<GoodsSource> list2 = goodsSourceMapper.selectByMap(map2);
                    List<QuantityDataVo> dataList = new ArrayList<>();
                    List<GoodsCancel> cancelList = new ArrayList<>();
                    for (GoodsSource source : list2) {
                        if (source.getSourceType().equals("其他收入")) {
                            GoodsCancel cancel = new GoodsCancel();
                            cancel.setApprovedAmount(source.getThisAmount());
                            cancel.setReceiptNumber(source.getSourceCode());
                            if(source.getUnwrittenAmount().subtract(source.getThisAmount()).compareTo(new BigDecimal(0))>0){
                                cancel.setStatus(1);
                            }else{
                                cancel.setStatus(3);
                            }
                            cancelList.add(cancel);
                        }else{
                            QuantityDataVo vo = new QuantityDataVo();
                            vo.setReceiptNumber(source.getSourceCode());
                            vo.setQuantity("1");
                            vo.setApprovedAmount(source.getThisAmount());
                            vo.setDocumentType(source.getSourceType());
                            dataList.add(vo);
                        }
                    }
                    if (!dataList.isEmpty()) {
                        UpdateInvoicedQuantityVo quantityVo = new UpdateInvoicedQuantityVo();
                        quantityVo.setList(dataList);
                        boolean flag = remotePurchaseReceiptService.updateInvoicedQuantity(quantityVo);
                        if (!flag) {
                            throw new GlobalException("核销金额未更新，请重试");
                        }
                    }
                    if (!cancelList.isEmpty()) {
                        for (GoodsCancel ca:
                        cancelList) {
                            goodsIncomeMapper.updateInvoicedCancel(ca);
                        }
                    }
                }
                break;
            case 2:
                goods.setCollectionStatus(3);
                break;
            case 3:
                if (data == 0) {
                    throw new GlobalException("不具备审核权限");
                }
                break;
            case 4:
                if (data == 0) {
                    throw new GlobalException("请勿重复审核");
                }
                break;
        }
        //审核人
        goods.setExamineBy(LoginHelper.getUsername());
        //审核日期
        goods.setExamineTime(new Date());
        return goodsCollectionMapper.updateById(goods);

    }

    @Override
    public TableDataInfo<Map<String, Object>> selectCes(GoodsCollectionVo goodSCollectionVo, PageQuery pageQuery) {
        String code = "client_code,client_name";
        Page<Map<String, Object>> page = goodsCollectionMapper.selectCes(code, pageQuery.build(), this.buildQueryWrapper(goodSCollectionVo));
        return TableDataInfo.build(page);
    }

    /**
     * 工作台接口(销售已收款金额)
     */
    @Override
    public String goodsReceived() {
        return goodsCollectionMapper.goodsReceived();
    }

    /**
     * 工作台接口(客户欠款金额)
     */
    @Override
    public String goodsArrears() {
        return goodsCollectionMapper.goodsArrears();
    }


    /**
     * 结账反结账（财务模块单据查询）
     */
    @Override
    public GoodsClosingDocumentDto closingCounterClosingDocument(String time) {
        GoodsClosingDocumentDto goodsClosingDocumentDto = new GoodsClosingDocumentDto();

        //收款单
        List<GoodsCollectionDto> qGoodsCollection = goodsCollectionMapper.getQClosingDocument(time);
        if (qGoodsCollection.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsCollectionDto> rGoodsCollection = goodsCollectionMapper.getRClosingDocument(time);
        boolean downGoodsCollection = rGoodsCollection.size() > 0;

        //付款单
        List<GoodsPaymentDto> qGoodsPayment = goodsPaymentMapper.getQClosingDocument(time);
        if (qGoodsPayment.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsPaymentDto> rGoodsPayment = goodsPaymentMapper.getRClosingDocument(time);
        boolean downGoodsPayment = rGoodsPayment.size() > 0;

        //其他收入单
        List<GoodsIncomeDto> qGoodsIncome = goodsIncomeMapper.getQClosingDocument(time);
        if (qGoodsIncome.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsIncomeDto> rGoodsIncome = goodsIncomeMapper.getRClosingDocument(time);
        boolean downGoodsIncome = rGoodsIncome.size() > 0;

        //其他支出单
        List<GoodsDisburseDto> qGoodsDisburse = goodsDisburseMapper.getQClosingDocument(time);
        if (qGoodsDisburse.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsDisburseDto> rGoodsDisburse = goodsDisburseMapper.getRClosingDocument(time);
        boolean downGoodsDisburse = rGoodsDisburse.size() > 0;

        //转账单
        List<GoodsTurnDto> qGoodsTurn = goodsTurnMapper.getQClosingDocument(time);
        if (qGoodsTurn.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsTurnDto> rGoodsTurn = goodsTurnMapper.getRClosingDocument(time);
        boolean downGoodsTurn = rGoodsTurn.size() > 0;

        //核销单
        List<GoodsNuclearDto> qGoodsNuclear = goodsNuclearMapper.getQClosingDocument(time);
        if (qGoodsNuclear.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsNuclearDto> rGoodsNuclear = goodsNuclearMapper.getRClosingDocument(time);
        boolean downGoodsNuclear = rGoodsNuclear.size() > 0;

        //成本调整
        List<GoodsCostAdjustmentDto> qGoodsCostAdjustment = goodsCostAdjustmentMapper.getQClosingDocument(time);
        if (qGoodsCostAdjustment.size() > 0) {
            throw new GlobalException("存在需要审批的单据，不能进行结账");
        }
        List<GoodsCostAdjustmentDto> rGoodsCostAdjustment = goodsCostAdjustmentMapper.getRClosingDocument(time);
        boolean downGoodsCostAdjustment = rGoodsCostAdjustment.size() > 0;

        if (downGoodsCollection || downGoodsPayment || downGoodsIncome || downGoodsDisburse || downGoodsTurn || downGoodsNuclear
            || downGoodsCostAdjustment) {
            goodsClosingDocumentDto.setStatusCode("2003");
            goodsClosingDocumentDto.setResultMessage("存在未完成的单据，是否继续结账");
            return goodsClosingDocumentDto;
        } else {
            goodsClosingDocumentDto.setStatusCode("2004");
            return goodsClosingDocumentDto;
        }
    }
}
